﻿using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Windows;
using System.Windows.Input;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System;
using HouseKeepingPL.HKService;
using System.Windows.Data;
using System.Windows.Documents;
using GalaSoft.MvvmLight.Messaging;

namespace HouseKeepingPL.ViewModel
{
    public class OutcomesViewModel : ViewModelBase
    {

        #region privates
        private ObservableCollection<Outcome> _outcomesList = null;
        private ObservableCollection<ActionType> _actionOutcomeTypes; // local action types list
        private bool _isNewOutcomeItem = true; // for cleaning outcome input fields
        private bool _cmdActionFlag = false; // action indicator for copy the income (i don't want the collection will be updated until button clicked)
        private User _currentUser = null; // current user logged

        #endregion
        public OutcomesViewModel()
        {
            #region messages registrations

            Messenger.Default.Register<ObservableCollection<ActionType>>(this, GetActionList);
            Messenger.Default.Register<User>(this, GetUser);

            #endregion

            #region relay commands

            // outcome relay commands
            CleanOutcomeInputCommand = new RelayCommand(() => CleanOutcomeInputCommandExcecute(), () => IsOutcomeItemSelected());
            AddOutcomeRowCommand = new RelayCommand(() => AddOutcomeRowCommandExcecute(), () => !IsOutcomeItemSelected());
            DeleteOutcomeRowCommand = new RelayCommand(() => DeleteOutcomeRowCommandExcecute(), () => IsOutcomeItemSelected());
            UpdateOutcomeRowCommand = new RelayCommand(() => UpdateOutcomeRowCommandExcecute(), () => IsOutcomeItemSelected());

            #endregion
        }

        #region messages actions
        private void GetActionList(ObservableCollection<ActionType> list)
        {
            ActionOutcomeTypes = list;
        }

        private void GetUser(User user)
        {
            _currentUser = user;
            if (user != null)
            {
                GetOutcomes = _currentUser.Outcomes1;
                CleanOutcomeInputCommandExcecute();      // add row option enabled for outcomes screen 
            }
        }

        #endregion

        #region helpers
        /// <summary>
        /// indicate for the buttons on the outcome tab whether it "can excecute" or not
        /// </summary>
        private bool IsOutcomeItemSelected()
        {
            return (!_isNewOutcomeItem);
        }

        /// <summary>
        /// Update local collection and DB data
        /// </summary>
        private int LocateOutcomeID(Outcome outcome)
        {
            bool bFlag = false;
            int index = 0;

            while ((!bFlag) && (index < _outcomesList.Count))
            {
                if (_outcomesList[index].Id == outcome.Id)
                {
                    bFlag = true;
                }
                ++index;
            }
            return (--index);

        }

        /// <summary>
        /// checks if outcome input object is equal to grid object to check if changes done
        /// </summary>
        /// <returns></returns>
        private bool CheckIfOutcomeInputEqGrid()
        {
            if ((CurrentlySelectedOutcome.Id == CurrentlySelectedOutcomeInput.Id) &&
                (CurrentlySelectedOutcome.Date == CurrentlySelectedOutcomeInput.Date) &&
                (CurrentlySelectedOutcome.Comment == CurrentlySelectedOutcomeInput.Comment) &&
                (CurrentlySelectedOutcome.ActionTypeId == CurrentlySelectedOutcomeInput.ActionTypeId) &&
                (CurrentlySelectedOutcome.Amount == CurrentlySelectedOutcomeInput.Amount))
                return true;

            return false;


        }

        /// <summary>
        /// Validation for Outcome input fields
        /// </summary>
        /// <returns>Error Code enum</returns>
        private ErrorCode ValidateOutcomeInputFields(bool supressMsgBox = false)
        {
            ErrorCode Result = ErrorCode.NoError;
            if (CurrentlySelectedOutcomeInput.Date == null)
            {
                Result = ErrorCode.DateFieldError;
                if (!supressMsgBox)
                    MyMessageBox.StopOk("Error occured in Date field", " Validation Error");
            }
            else if (String.IsNullOrEmpty(CurrentlySelectedOutcomeInput.Comment))
            {
                Result = ErrorCode.CommentFieldError;
                if (!supressMsgBox)
                    MyMessageBox.StopOk("Error occured in comment field", " Validation Error");
            }
            else if ((CurrentlySelectedOutcomeInput.Amount <= 0) || (CurrentlySelectedOutcomeInput.Amount > Decimal.MaxValue))
            {
                Result = ErrorCode.AmountFieldError;
                if (!supressMsgBox)
                    MyMessageBox.StopOk("Error occured in Amount field", " Validation Error");
            }
            else if (CurrentlySelectedOutcomeInput.ActionTypeId == 0)
            {
                Result = ErrorCode.ActionTypeFieldError;
                if (!supressMsgBox)
                    MyMessageBox.StopOk("Error occured in action field", " Validation Error");
            }


            return Result;
        }

        #endregion

        #region Outcome
        
        /// <summary>
        /// deletes selected row from the DB
        /// </summary>
        private void DeleteOutcomeRowCommandExcecute()
        {
            if ((MyMessageBox.Confirm("Are you sure you want to delete?", "Please confirm") == MessageBoxResult.Yes))
            {
                try
                {
                    ClientProxy.Proxy.DeleteOutcome(CurrentlySelectedOutcome.Id); // send server delete command
                    _outcomesList.Remove(CurrentlySelectedOutcome); // delete from local list as well
                }
                catch
                {
                    MyMessageBox.ErrorOk("Error occured while delete from the DB", "DB Error");
                }
            }
        }

        /// <summary>
        /// Add a fields to the DB and the local collecition
        /// </summary>
        private void AddOutcomeRowCommandExcecute()
        {
            if (CurrentlySelectedOutcomeInput != null)
            {
                if (ValidateOutcomeInputFields() == ErrorCode.NoError)
                {
                    CurrentlySelectedOutcomeInput.UsersId = _currentUser.Id;
                    int newID = ClientProxy.Proxy.InsertOutcome(CurrentlySelectedOutcomeInput);
                    CurrentlySelectedOutcomeInput.Id = newID;
                    _outcomesList.Add(CurrentlySelectedOutcomeInput);
                    CleanOutcomeInputCommandExcecute();
                }
            }

        }

        /// <summary>
        /// Update fields of outcome
        /// </summary>
        private void UpdateOutcomeRowCommandExcecute()
        {
            _cmdActionFlag = true;
            if (!CheckIfOutcomeInputEqGrid())
            {
                if ((MyMessageBox.Confirm("Are you sure you want to Update?", "Please confirm") == MessageBoxResult.Yes))
                {
                    if (ValidateOutcomeInputFields() == ErrorCode.NoError)
                    {
                        int indexOfUpdatedOutcome = LocateOutcomeID(CurrentlySelectedOutcome);
                        try
                        {
                            ClientProxy.Proxy.UpdateOutcome(CurrentlySelectedOutcomeInput); // update DB
                        }
                        catch
                        {
                            MyMessageBox.ErrorOk("Error occured while updating from the DB", "DB Error");
                        }

                        _outcomesList[indexOfUpdatedOutcome] = CurrentlySelectedOutcomeInput;
                        CleanOutcomeInputCommandExcecute();

                        if (_outcomesList.Count > 0)
                            CurrentlySelectedOutcome = _outcomesList[indexOfUpdatedOutcome];
                    }
                }
            }
            else
                MyMessageBox.InfoOk("No changes Detected", "Notification");



            _cmdActionFlag = false;
        }

        /// <summary>
        /// Clean the input fields and ready for add row
        /// </summary>
        private void CleanOutcomeInputCommandExcecute()
        {
            CurrentlySelectedOutcome = null;
            _isNewOutcomeItem = true;
            IsOutcomeItemSelected();

            try
            {
                CurrentlySelectedOutcomeInput = new Outcome()
                {
                    Date = DateTime.Now,
                    Comment = string.Empty,
                    Amount = 0,
                    ActionTypeId = ActionOutcomeTypes[0].Id
                };
            }
            catch (NullReferenceException ex)
            {
                MyMessageBox.ErrorOk("no outcome types available!", "Critical Error");
            }

        }



        

        #region BindProperties

        /// <summary>
        /// from the grid, and update the DB after confirmation
        /// </summary>
        private Outcome _currentlySelectedOutcome;
        public Outcome CurrentlySelectedOutcome
        {
            get
            {
                _isNewOutcomeItem = false;
                IsOutcomeItemSelected();
                if ((this._currentlySelectedOutcome != null) && (_cmdActionFlag == false))
                {
                    _currentlySelectedOutcomeInput = new Outcome() //copy ctor "like"
                    {
                        Id = this._currentlySelectedOutcome.Id,
                        UsersId = _currentUser.Id,
                        Date = this._currentlySelectedOutcome.Date,
                        Amount = this._currentlySelectedOutcome.Amount,
                        Comment = this._currentlySelectedOutcome.Comment,
                        ActionTypeId = this._currentlySelectedOutcome.ActionTypeId

                    };
                }
                RaisePropertyChanged("CurrentlySelectedOutcomeInput");
                return this._currentlySelectedOutcome;
            }
            set
            {
                this._currentlySelectedOutcome = value;

                RaisePropertyChanged("CurrentlySelectedOutcome");
            }
        }

        /// <summary>
        /// binded to the input controls
        /// </summary>
        private Outcome _currentlySelectedOutcomeInput;
        public Outcome CurrentlySelectedOutcomeInput
        {
            get
            {
                return this._currentlySelectedOutcomeInput;
            }
            set
            {
                if (_currentlySelectedOutcomeInput == null)
                {
                    _currentlySelectedOutcomeInput = new Outcome()
                    {
                        Date = DateTime.Now,
                        Comment = string.Empty,
                        Amount = 0,
                        ActionTypeId = ActionOutcomeTypes[0].Id
                    };
                }

                this._currentlySelectedOutcomeInput = value;
                RaisePropertyChanged("CurrentlySelectedOutcomeInput");
            }
        }


        public ObservableCollection<ActionType> ActionOutcomeTypes
        {
            get
            {
                return _actionOutcomeTypes;
            }
            set
            {
                _actionOutcomeTypes = value;
                RaisePropertyChanged("ActionOutcomeTypes");
            }
        }
        private ActionType _CurrentlySelectedActionOutcomeType;
        public ActionType CurrentlySelectedActionOutcomeType
        {
            get { return _CurrentlySelectedActionOutcomeType; }
            set { _CurrentlySelectedActionOutcomeType = value; }
        }

        public ObservableCollection<Outcome> GetOutcomes
        {
            get
            {
                return _outcomesList;
            }
            set
            {
                _outcomesList = value;
                RaisePropertyChanged("GetOutcomes");

            }


        }

        #endregion

        #endregion

        #region Command properties

        public ICommand CleanOutcomeInputCommand { get; private set; }
        public ICommand AddOutcomeRowCommand { get; private set; }
        public ICommand DeleteOutcomeRowCommand { get; private set; }
        public ICommand UpdateOutcomeRowCommand { get; private set; }

        #endregion



    }
}




